#! /usr/bin/env python
##   ouat.py
##   $Id$
##   Copyright (C) 2007 Sean Lin
##
##   This program is free software; you can redistribute it and/or modify
##   it under the terms of the GNU General Public License as published by
##   the Free Software Foundation; either version 2, or (at your option)
##   any later version.
##
##   This program is distributed in the hope that it will be useful,
##   but WITHOUT ANY WARRANTY; without even the implied warranty of
##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##   GNU General Public License for more details.

import common.xmpp as xmpp
import common.Reactor as Reactor
import types
import sys
import game
import user
import time
import status
from Game_Hall import GameHall
try:
    from bot_conf import conf
except:
    print "Can't read the configure file: bot_conf.py"
    print "maybe you must copy bot_conf.py.default to bot_conf.py"
    sys.exit(1)

from common.gbase import if_gbase

sys_conf = \
    {'sysprompt': '>>>',
    }

On_Hall_User=[]
conn=[]

class Profile(xmpp.JID):
    def __init__(self, jid, server=None,proxy=None,passwd=None):
        xmpp.JID.__init__(self, jid)
        
        self._server = server
        self._proxy = proxy

        if passwd:
            self._passwd = passwd
        else:
            self._passwd = ''
    def getPasswd(self):
        return self._passwd
    def setPasswd(self,passwd):
        self._passwd=passwd
    def getServer(self):
        return self._server
    def setServer(self,server):
        self._server=server
    def getProxy(self):
        return self._proxy
    def setProxy(self,proxy):
        self._proxy=proxy
    def setJID(self,jid):
        self.JID.__init__(self, jid)


class Bot(Reactor.Handler):
    def __init__(self,profile,conf,conn,reactor):
        Reactor.Handler.__init__(self,reactor)
        self.__profile = profile
        self.__conn = conn
        self.__hall = GameHall(profile,conf, conn, reactor)
        self.__last_ping = 0
        self.__status = status.get_status()
        self.__status_counter = 0

    def handle_input(self):
        self.StepOn()
        return 0
    
    def messageCB(self,conn,mess):
        text=mess.getBody()
        user=unicode(mess.getFrom())
        if mess.getError()!=None:
            return
        if mess.getFrom().getNode().lower() == self.__profile.getNode().lower():
            return
        if self.__hall.user_is_in(user):
            self.__hall.process_message(mess)
        else:
            self.__hall.add_user(user)
            self.__hall.process_message(mess)

    def presenceCB(self, con,prs):
        who = unicode(prs.getFrom())
        pr_status = prs.getStatus()
        if pr_status == 'None' or pr_status == None:
            pr_status = ''
        else:
            pr_status = unicode(pr_status)
        if prs.getFrom().getNode().lower() == self.__profile.getNode().lower():
            return
        type = prs.getType()
        # TODO: Try only acking their subscription when they ack ours.
        if type == 'subscribe':
            print "Accepted"
            con.send(xmpp.Presence(to=who, typ='subscribed'))
            con.send(xmpp.Presence(to=who, typ='subscribe'))
            self.__hall.add_user(who, pr_status)
        elif type == 'subscribed':
            self.__hall.add_user(who, pr_status)
        elif type == 'unsubscribed':
            self.__hall.remove_user(who)
        elif type == 'unavailable':
            r = self.__conn.getRoster()
            roster = r.getItem(prs.getFrom().getStripped())
            if roster:
                if len(roster['resources'])>1 :
                    return;
            self.__hall.remove_user(who)
        elif type == 'available' or type == None:
            self.__hall.add_user(who, pr_status)
        else:
            pass

    def iqCB(self, con,iq):
        # reply to all IQ's with an error
        reply=None
        try:
            # Google are bad bad people
            # they don't put their query inside a <query> in <iq>
            reply=xmpp.Iq(to=iq.getFrom(),type='error')
            stuff=iq._node.getChildren()
            for i in stuff:
                reply._node.insertNode(i)
            reply.setError('501', _('Feature not implemented'))
            con.send(reply)
        except:
            return
            traceback.print_exc()

    def StepOn(self):
        self.__conn.Process(0)
        return

    def change_status(self, args):
        # Say we're online.
        p = xmpp.Presence()
        jid=self.__conn.User+'@'+self.__conn.Server+'/'+self.__conn.Resource
        p.setFrom(jid)
        self.__conn.send(p)
        p = xmpp.Presence()
        self.__status_counter += 1
        if self.__status_counter > 15: # every half a hour
            self.__status_counter = 0
            self.__status = status.get_status()
        p.setStatus(self.__status)
        self.__conn.send(p)
        self.reactor.register_timer(120, self.change_status, (args))

    def loop(self):
        while self.StepOn(): pass
    
    def connect(self):
        conres=self.__conn.connect(self.__profile.getServer(),self.__profile.getProxy())
        if not conres:
            print "Unable to connect to server %s!"%profile.getDomain()
            sys.exit(1)
        if conres<>'tls':
            print "Warning: unable to estabilish secure connection - TLS failed!"
        self.__conn.RegisterHandler('message',self.messageCB)
        self.__conn.RegisterHandler('presence',self.presenceCB)
        self.__conn.RegisterHandler('iq',self.iqCB)
        authres=self.__conn.auth(self.__profile.getNode(), self.__profile.getPasswd(), self.__profile.getResource())
        if not authres:
            print "Unable to authorize on %s - check login/password."%profile.getDomain()
            sys.exit(1)
        if authres<>'sasl':
            print "Warning: unable to perform SASL auth os %s. Old authentication method used!"%profile.getDomain()
        self.__conn.sendInitPresence()
        self.fd = self.__conn.sock()
        self.reactor.register_handler(self,Reactor.READ_MASK)
        self.reactor.register_timer(0, self.change_status, "change_status")
        print "Bot started."
        return self.__conn.sock()

def main():
    profile = Profile(**conf)
    reactor = Reactor.Reactor()
    global conn
    conn=xmpp.Client(profile.getDomain())#,debug=["socket"])
    bot = Bot(profile, sys_conf, conn, reactor)
    #if_gbase.init(conf)
    bot.connect()
    try:
        reactor.run()
    except KeyboardInterrupt: return 0
    return 1
    pass

if __name__ == '__main__':
    main()
